ddos and flood problem for phpbb

This is an archive of the phpBB 2.0.x support forum. Support for phpBB2 has now ended.
Forum rules
Following phpBB2's EoL, this forum is now archived for reference purposes only.
Please see the following announcement for more information: viewtopic.php?f=14&t=1385785
Locked
koncilo
Registered User
Posts: 2
Joined: Mon Dec 19, 2005 2:54 pm

ddos and flood problem for phpbb

Post by koncilo »

Hello to everybody

First, sorry for my bad english but i have to write my problem here. I hope everybody will understand me.

I have a phpbb forum on my site and my site is since one month under ddos and flood attack.
The hackers attacking to the site IP number, the port 80 and to the /forum/index.php. For that reason, sometimes my site is become inaccesible. I have a VPS account on a server and by restarting my VPS, only for few seconds i can login to my forum directory. I see too much connections on the admin page.

My question is: is there a script or another way to stop the simultaneous multiple connections from an IP address?

Thanks...

User avatar
Ruder
Registered User
Posts: 23
Joined: Thu Nov 17, 2005 4:08 pm
Location: Germany
Contact:

Post by Ruder »

I have a VPS account on a server and by restarting my VPS, only for few seconds i can login to my forum directory. I see too much connections on the admin page


if you have root access to a (virtual) server you could check if you can block IP addresses in your server admin panel.

If it's an apache webserver you can try to upload a ".htaccess" file to your webserver document root. You can ban IP addresses or domains
Just make a file called ".htaccess" and put
"Deny from" followed by either IP or domainname.

example:

Code: Select all

# Start Autobanlist
Deny from dr.home.nl
Deny from 217.120.33.11

koncilo
Registered User
Posts: 2
Joined: Mon Dec 19, 2005 2:54 pm

Post by koncilo »

Thank you very much for your early response Ruder. but this method is not a good solution. I have been tested this method and it is not successful. Because the hacker groups making the DDOS attack with several computers and, anytime they can change their IP addresses. I have to watch on the forum to determine IP address for banning. I want to a script which will stop the multiple connections automatically.

Thank you again.

Taipo
Registered User
Posts: 174
Joined: Fri Jan 07, 2005 9:25 pm
Contact:

Post by Taipo »

This script below will do the trick. It is however a difficult thing to decipher which IPs are legitimate and which ones are attack IPs. What this does is first tests that the viewing client can understand javascript, then can it understand cookies, if not then the page will not be displayed. Most HTTP request flooder tools (assuming this is an HTTP request flood) are not javascript or cookie enabled. If these apps cannot translate the javascript and cookie commands then a one line warning message is displayed instead of the whole page loading thus cutting down bandwidth comsumption.

This script also begins a timer of connections per ip per amount of secs and if there are too many http requests from that ip it is appended to your htaccess as a ban.

As this is not an accurate science in a sense that some legitimate users may get their IP addresses netted as well, i tend to empty out the IP list after a flood attempt.

Step one:

add a file called .htaccess to your web folder and channel mod it to 666 to allow this script to write ip addresses to it.

step two:
create a file using this script below called c_security.php and upload to your web folder.

Code: Select all

<?php
#############################################################################
#
# Cafe CounterIntelligence SoapCMS Core Security Class
# Copyright 2004 Mike Parniak
# www.cafecounterintelligence.com
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# 
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Purpose: Base flood, XSS and SQL Injection protection
#
# Requires: Nothing.
#
# Usage: create an instance of the soapSecurity object at the beginning of
#		 any publically accessible scripts.  GET, POST, and COOKIE variables
#		 that are strictly numeric should begin with "n_".  
#
#############################################################################

class soapSecurity {

  var $ip;  
  var $csUn			= "Soap";
  var $vkeyname; 	
  var $vhash;
  var $vsession; 	
  var $vsesscook; 
  var $config;   
  var $translation_table;
  var $translation_string;
    
######################

  // Initialization function

function soapSecurity($dosanitize = 1) {
    global $conf;
    list($usec, $sec) = explode(' ', microtime());
    srand((float) $sec + ((float) $usec * 1234577));
    
    $this->config = &$conf;
   
    ini_set("session.use_cookies","On");
    ini_set("session.use_only_cookies","1");
    ini_set("session.use_trans_sid","0");
    
    $this->translation_table = array_merge(range('0','9'),range('A','Z'),range('a','z')); 
    $this->translation_string = implode('',$this->translation_table);   
    
    $ip = $_SERVER["REMOTE_ADDR"];
    $vkeyname = md5($_SERVER["REMOTE_ADDR"] . $_SERVER["HTTP_HOST"] . $_SERVER["DOCUMENT_ROOT"] . $csUn);
    $vhash = md5($_SERVER["REMOTE_ADDR"] . $_SERVER["HTTP_USER_AGENT"] . 
						$_SERVER["HTTP_HOST"] . $_SERVER["DOCUMENT_ROOT"] . 
						$_SERVER["SERVER_SOFTWARE"] . $_SERVER["PATH"] . $csUn);
 	$vsession = md5($_SERVER["REMOTE_ADDR"] . $_SERVER["HTTP_HOST"] . $csUn);
 	$vsesscook = md5($_SERVER["REMOTE_ADDR"] . $_SERVER["DOCUMENT_ROOT"] . $_SERVER["HTTP_HOST"]);   
   
  	srand(time());
	session_name($vhash); 
	session_id($vsession);	// Begin data-specific session
    session_start();   
    
    if (($_SESSION["amalive"] == "1") && ($_SESSION["sesstime"]<(time()-3600))) {
      setcookie($vsesscook,"",0,"/");
      session_unset();
      session_destroy();
      unset($_COOKIE["$vsesscook"]);
      
      session_name($vhash); 
	  session_id($vsession);	// Begin data-specific session
      session_start();
    }
    $_SESSION["amalive"] = '1';
    $_SESSION["sesstime"] = time();
    
    $REQUEST_URI = $_SERVER["SCRIPT_NAME"];
    $REQUEST_URI = eregi_replace(".*_non_ssl","",$REQUEST_URI);
    if ($_SERVER["QUERY_STRING"] != "") $REQUEST_URI .= "?" . $_SERVER["QUERY_STRING"];
    
    if ((!isset($_SESSION["soapsec-rtg"])) || ($_SESSION["soapsec-rtg"]<1)) {
  	  $_SESSION["soapsec-rtg"] = rand(1,3);
      $_SESSION["soapsec-romps"] = 0;
      $_SESSION["soapsec-ourl"] = $REQUEST_URI;
      $_SESSION["soapsec-rcode"] = md5($_SERVER["REMOTE_ADDR"] . $_SERVER["HTTP_USER_AGENT"] . 
				$_SERVER["HTTP_HOST"] . $_SERVER["DOCUMENT_ROOT"] . 
				$_SERVER["SERVER_SOFTWARE"] . $_SERVER["PATH"] . $_SESSION["soapsec-romps"] . time());
    }
    
    if (($_SESSION["soapsec-rtg"]>0) && ($_SESSION["soapsec-romps"]<$_SESSION["soapsec-rtg"])) {
      if (($_GET[$vkeyname] == $_SESSION["soapsec-rcode"]) && ($_GET[$vkeyname] != "")) {
        $_SESSION["soapsec-romps"]++;
      } else $_SESSION["soapsec-errors"]+=2;
      if ($_SESSION["soapsec-romps"] < $_SESSION["soapsec-rtg"]) {
        $_SESSION["soapsec-rcode"] = md5($_SERVER["REMOTE_ADDR"] . $_SERVER["HTTP_USER_AGENT"] . 
			$_SERVER["HTTP_HOST"] . $_SERVER["DOCUMENT_ROOT"] . 
			$_SERVER["SERVER_SOFTWARE"] . $_SERVER["PATH"] . $_SESSION["soapsec-romps"] . time());
		$numromps = $_SESSION["soapsec-romps"];
        session_write_close();
        $thisurl = $REQUEST_URI;
        $thisurl = eregi_replace("\?.*","",$thisurl);
        $thisurl = "http://" . $_SERVER["SERVER_NAME"] . $thisurl . "?"; 
        $outkey = $vkeyname . "=" . $_SESSION["soapsec-rcode"];
    
    	// First romp is less CPU intensive, in cases of weak automated requesters.
    	
    	// Second romp includes automatic timezone detection
    
        if ($numromps==1) {  
          header("Location: " . $thisurl . $outkey);
          exit();
        }         
        // Subsequent romps are tricky, using hard-to-parse javascript.
    
	    $rnu = rand(8,15);
    	$ran = array();
    	$jsout = "<SCRIPT LANGUAGE=\"JavaScript\">\n";
    	for ($i = 0;$i < $rnu;$i++) {
      	  $ran[$i] = rand(-65,65);
          $jsout .= "var " . chr(97+$i) . " = " . $ran[$i] . "; ";
        }
    
        $outlen = strlen($outkey);
 
        $jsout .= "var z = new Array(); ";
        $myvars = array();
    
        $onvar = 0;
        for ($i = 0;$i < $outlen;$i++) {
          if ($onvar >= $rnu) $onvar = 0;
          $thediff = $i - $ran[$onvar];
      	  $myvars[$i] = "z[" . chr(97+$onvar);
          if ($thediff>0) $myvars[$i].= "+";
          if ($thediff<>0) $myvars[$i] .= $thediff;
          $myvars[$i] .= "] = \"" . $outkey[$i] . "\"; ";
          $onvar++;  
        }
        shuffle($myvars);
        $jsout .= implode('',$myvars);
        $jsout .= "var x = z.join(\"\"); ";
        $jsout .= "location.replace(\"" . $thisurl . "\" + x);</SCRIPT><noscript>You must enable Javascript in order to view this webpage.</noscript>";
        echo $jsout;
      } else {
        $thisurl = "http://" . $_SERVER["SERVER_NAME"] . $_SESSION["soapsec-ourl"];
        echo "<SCRIPT LANGUAGE=\"JavaScript\">location.replace(\"$thisurl\");</SCRIPT><noscript>You must enable Javascript in order to view this webpage.</noscript>";
      }  
      exit();  
    }
    
    if ($dosanitize) {
     
      $getvariables = array_keys($_GET);
      $count = 0;
      while($count < count($getvariables)) {
        $_GET[$getvariables[$count]] = $this -> sanitize($_GET[$getvariables[$count]],(strpos($getvariables[$count],"n_")===0));
        $count++;
      }
      $getvariables = array_keys($_POST);
      $count = 0;
      while($count < count($getvariables)) {
        $_POST[$getvariables[$count]] = $this -> sanitize($_POST[$getvariables[$count]],(strpos($getvariables[$count],"n_")===0));
        $count++;
      }
      $getvariables = array_keys($_COOKIE);
      $count = 0;
      while($count < count($getvariables)) {
        $_COOKIE[$getvariables[$count]] = $this -> sanitize($_COOKIE[$getvariables[$count]],(strpos($getvariables[$count],"n_")===0));
        $count++;
      }        
    } 
    
    // If server has automatic global creation, destroy automatically created variables.
    // but... make sure that the variable's value matches the request variable's value before destroying it.
    
    $getvariables = array_keys($_REQUEST);
    $count = 0;
    while($count < count($getvariables)) {
      if ((isset($getvariables[$count])) && ($GLOBALS[$getvariables[$count]] == $_REQUEST[$getvariables[$count]])) {
        unset($GLOBALS[$getvariables[$count]]);
      }
      $count++;
    }
    
    // Remove our session and initiate or restore the user session.
     
    if (isset($_COOKIE["$vsesscook"])) {
      session_write_close();
      session_name($vsesscook); 
	  session_id($_COOKIE["$vsesscook"]);	
      session_start(); 
             
      if ((!isset($_SESSION["soap-flag"])) || ((!isset($_SESSION["time_offset"])) && (!isset($_GET["n_offset"])))) {
        setcookie($vsesscook,"",0,"/");
        session_unset();
        session_destroy();
        unset($_COOKIE["$vsesscook"]);    
        Header("Location: http://" . $_SERVER["SERVER_NAME"] . $REQUEST_URI);
        exit(); 
      }
      
      if ($_GET["rewind"] == 2) {
        setcookie($vsesscook,"",0,"/");
        session_unset();
        session_destroy();
        unset($_COOKIE["$vsesscook"]);    
        Header("Location: http://www.aocafe.com/forums/");
        exit();      
      }
      
      if (!isset($_SESSION["time_offset"])) {
        // $_SESSION["time_offset"] = intval((($_GET["n_offset"]/1000)-time())+(time()-gmmktime()),10);
        $_SESSION["time_offset"] = intval(($_GET["n_offset"]/1000)-gmmktime(),10);
        $_SESSION["tz_offset"] = $_GET["n_tzoff"];
        Header("Location: http://" . $_SERVER["SERVER_NAME"] . $_SESSION["ourl"]);
        exit();         
      }
      
    } else {
      if ((time()-120)<$_SESSION["soapsec-lastsess"]) {
        if ($_SESSION["soapsec-fastsess"]>2) {
          $_SESSION["soapsec-lastsess"] = time();
          bancheck("fastsess",2);
        }
      } else $_SESSION["soapsec-fastsess"] = 0;
    
      $_SESSION["soapsec-lastsess"] = time();
      $_SESSION["soapsec-fastsess"]++;
      session_write_close;
      session_name($vsesscook);
      session_id(md5(uniqid(time())));
      session_start();
      setcookie($vsesscook,session_id(),0,"/");
      $_SESSION["soap-flag"] = 1;
      
	  $tempTable = $this->translation_table;
	  shuffle($tempTable); // ... create one.
	  $_SESSION['jprivatekey'] = $key = implode('',$tempTable);

$_SESSION["ourl"] = $REQUEST_URI;
      $thisurl = $REQUEST_URI;
      $thisurl = eregi_replace("\?.*","",$thisurl);
      $thisurl = "http://" . $_SERVER["SERVER_NAME"] . $thisurl . "?";   
      $jsout  = "<SCRIPT LANGUAGE=\"JavaScript\">\n";
      $jsout .= "d = new Date();\n";
      $jsout .= "x = d.getTimezoneOffset() * 60000; x = d.valueOf() - x;";
      $jsout .= "location.replace(\"" . $thisurl . "n_offset=\" + x + \"&n_tzoff=\" + d.getTimezoneOffset());</SCRIPT>";
      echo $jsout;
      exit();
    }

     $usehtaccess1 = 2;
     if ($this -> floodcheck("fastaccess",2,6)) {
      switch($usehtaccess1) {

	case (2):
	 htaccessban($_SERVER["REMOTE_ADDR"]); 
         exit();

	case (1):
	 bancheck("fastaccess",15);
         exit();

	case (0):
	 die(); 

	default:
	 die();
      }

    }


    return; 
  }

  
  // Removes potentially hazardous material from a string (anti-XSS, anti-Injection)
  // Reliable anti-injection requires cgi variables use the n_ naming convention for any
  // variable that is strictly numeric and possibly used in a query.
    
  function sanitize($tosanitize,$numonly=FALSE) {
    if (is_array($tosanitize)) {
      foreach($tosanitize as $myitem) {
        $myitem = $this->sanitize($myitem,$numonly);
      }
      return $tosanitize;  
    }
    if ($numonly) {
      $tosanitize = eregi_replace("[^0-9\.\-]","",$tosanitize);
    } else {
      $tosanitize = htmlspecialchars($tosanitize);
      $tosanitize = eregi_replace("javascript:","java&#00;script:",$tosanitize);
      if (!get_magic_quotes_gpc()) $tosanitize = addslashes($tosanitize);
    }
    return $tosanitize;
  }  
  
  // Decide on possible long-term penalty
  
  function bancheck($identifier,$threshold=10) {
    $myresult = 0;
    if ($this->conf->get("sec_htaccess_bans")) {
      if ((isset($_SESSION["soapsec-" . $identifier . "-rep"])) || ($threshold == 1)) {
        if ((++$_SESSION["soapsec-" . $identifier . "-rep"]) >= $threshold) {
          $this->htaccessban($this->$ip);
        }
      } else $_SESSION["soapsec-" . $identifier . "-rep"] = 1;
    }
    exit();
  }



  // Generic flood checking routine    
  
  function floodcheck($identifier,$interval,$threshold=1) {
    $myresult = 0;
    if (isset($_SESSION["soapsec-" . $identifier])) {
      if ($_SESSION["soapsec-" . $identifier] > (time()-$interval)) {
        if ($threshold<2) {
          $myresult = 1;
        } else {
          if (!isset($_SESSION["soapsec-" . $identifier . "-counter"])) {
            $_SESSION["soapsec-" . $identifier . "-counter"] = 1;
          } else {
            $_SESSION["soapsec-" . $identifier . "-counter"]++;
            if ($_SESSION["soapsec-" . $identifier . "-counter"] >= $threshold) {
              $myresult = 1;
            }
          }
        }
      } else $_SESSION["soapsec-" . $identifier . "-counter"] = 1;
    }
    $_SESSION["soapsec-" . $identifier] = time();
    return $myresult; 
  }  
  

  function htaccessban($banip) {

    $filelocation = $_SERVER['DOCUMENT_ROOT'] . "/.htaccess";
    $limitend = "# End of soapSecurity Section 2\n";
    $newline = "deny from $banip\n";
    if (file_exists($filelocation)) {
      $mybans = file($filelocation);
      $lastline = "";
      if (in_array($newline,$mybans)) exit();
      if (in_array($limitend,$mybans)) {      
        $i = count($mybans)-1;
        while ($mybans[$i] != $limitend) {
          $lastline = array_pop($mybans) . $lastline;
          $i--;
        }
        $lastline = array_pop($mybans) . $lastline;
        $lastline = array_pop($mybans) . $lastline;
        $lastline = array_pop($mybans) . $lastline;
        array_push($mybans,$newline,$lastline);
      } else {
        array_push($mybans,"\n\n# soapSecurity Script 2\n","<Limit GET POST>\n","order allow,deny\n",$newline,"allow from all\n","</Limit>\n",$limitend);
      }
    } else {
      $mybans = array("# soapSecurity Script 2\n","<Limit GET POST>\n","order allow,deny\n",$newline,"allow from all\n","</Limit>\n",$limitend);
    }  
    $myfile = fopen($filelocation,"w");
    fwrite($myfile,implode($mybans,""));
    fclose($myfile);  
  }  


  function decrypt_string($input_string) {
    return strtr($input_string,$this->translation_string,$_SESSION["jprivatekey"]);
  }
  
  function encrypt_string($input_string) {
    return strtr($input_string,$_SESSION["jprivatekey"],$this->translation_string);
  }
  
  function getPOST($variable_name) {
    return $_POST[$this->encrypt_string($variable_name)];
  }
  
  function getGET($variable_name) {
    return $_GET[$this->encrypt_string($variable_name)];
  }
  
  function showTable() {
    echo $this->translation_string;
  }

  }

  function htaccessban($banip) {

    $filelocation = $_SERVER['DOCUMENT_ROOT'] . "/.htaccess";
    $limitend = "# End of soapSecurity Section 2\n";
    $newline = "deny from $banip\n";
    if (file_exists($filelocation)) {
      $mybans = file($filelocation);
      $lastline = "";
      if (in_array($newline,$mybans)) exit();
      if (in_array($limitend,$mybans)) {      
        $i = count($mybans)-1;
        while ($mybans[$i] != $limitend) {
          $lastline = array_pop($mybans) . $lastline;
          $i--;
        }
        $lastline = array_pop($mybans) . $lastline;
        $lastline = array_pop($mybans) . $lastline;
        $lastline = array_pop($mybans) . $lastline;
        array_push($mybans,$newline,$lastline);
      } else {
        array_push($mybans,"\n\n# soapSecurity Script 2\n","<Limit GET POST>\n","order allow,deny\n",$newline,"allow from all\n","</Limit>\n",$limitend);
      }
    } else {
      $mybans = array("# soapSecurity Script 2\n","<Limit GET POST>\n","order allow,deny\n",$newline,"allow from all\n","</Limit>\n",$limitend);
    }  
    $myfile = fopen($filelocation,"w");
    fwrite($myfile,implode($mybans,""));
    fclose($myfile);  
  }  

?>
Step three:

add this to your extension.inc second line from top

Code: Select all

require_once("/home/pathto/public_html/c_security.php");
$mysecurity = new soapSecurity();
change the path to point to where you uploaded the script.

User avatar
Ruder
Registered User
Posts: 23
Joined: Thu Nov 17, 2005 4:08 pm
Location: Germany
Contact:

Post by Ruder »

ah, i understood you were dealing with just one IP,sorry.

So it's a real automated ddos like stacheldraht or Tribe.
I'd say talk to your ISP and try to fight back on server level.
Good luck

Taipo
Registered User
Posts: 174
Joined: Fri Jan 07, 2005 9:25 pm
Contact:

Post by Taipo »

So it's a real automated ddos like stacheldraht or Tribe.
I'd say talk to your ISP and try to fight back on server level.
Good luck


If it is an HTTP request flood it will be very difficult to distinguish between legitimate page requests and flood requests especially if the tool being used is Jackhammer or any of the clones of this tool. A single attacker can use an anonymous proxy list with an unlimited list of proxys they can find readily available at any of the many proxy websites. This means that you may not see another request from that single IP for up to a minute as jackhammer styled tools toggle through a list of say 1000 proxy servers each one requesting that page.

Taipo
Registered User
Posts: 174
Joined: Fri Jan 07, 2005 9:25 pm
Contact:

Post by Taipo »

Another quick and very nasty way where you know the user-agent these attack tools are sending is to call a page die if certain user-agents or no user-agent is sent in the HTTP request.

This of course is a crap fix as the user-agent can be spoofed to say anything the attacker wants to be said, but its worth a try anyways.

extension.inc
add this next line down below <?php

Code: Select all

$die2bots = '1';
$ua1 = '';
$ua2 = 'Site Smashing Clan'; // change this to the useragent of the attacker

$useragent = (isset($HTTP_SERVER_VARS['HTTP_USER_AGENT'])) ? $HTTP_SERVER_VARS['HTTP_USER_AGENT'] : getenv('HTTP_USER_AGENT');

if($die2bots == '1') {
	if (strpos($useragent, $ua1)!==false) {
	die();
	} elseif (strpos($useragent, $ua2)!==false) {
	die();
   }
}
all this does is look at the useragent and if there isnt one or the useragent says something like 'Site Smashing Clan' (change that to whatever useragent their attack tools are sending) then it will kill the page for that IP address thus greatly reducing your bandwidth consumption.

warning: do not change that to a legitimate user-agent or it will call die() for your regular site visitors.

Locked

Return to “2.0.x Support Forum”