From a73654d9b06857e386c7bc4b74e3b47580d64669 Mon Sep 17 00:00:00 2001 From: Hong Phuc Nguyen Date: Sat, 5 Nov 2016 09:29:46 +0700 Subject: [PATCH] Release v1.1 --- README.md | 64 ++++++++++++++++++++++++++++++++++++++++++++++ analyser.php | 62 ++++++++++++++++++++++++++++++++++++++++++++ logparser.php | 63 +++++++++++++++++++++++++++++++++++++++++++++ runddosfirewall.sh | 8 ++++++ 4 files changed, 197 insertions(+) create mode 100644 README.md create mode 100644 analyser.php create mode 100644 logparser.php create mode 100644 runddosfirewall.sh diff --git a/README.md b/README.md new file mode 100644 index 0000000..e639971 --- /dev/null +++ b/README.md @@ -0,0 +1,64 @@ +--------------------------------- + + XNOHAT DDoS FIREWALL + + Version: 1.1 + + xnohat@gmail.com + +----------------------------------- + +INSTRUCTION + +Notes: + +For CentOS only, modify yourself for other distros + +/!\ Must do: Stop all Web/HTTPD Services and Database Services for free resources first + +[!] Recommend: ++ Using this firewall script on your reverse proxy ++ Block all traffic to your main (upstream) server except traffic from Reverse Proxy ++ Implement DNS Round robin with multiple reverse proxies to reduce DDoS load first ++ Contact ISP to upgrade your server BANDWIDTH, RAM, CPU, HDD to maximum of your budget first. I suggest: 4-8 Cores CPU, 16-32 GB RAM, 50 GB SSD, Port 1Gbps NIC Bandwidth + +Step-by-step + +$ yum install epel-release + +$ yum install nload tmux + +$ yum install php php-pdo + +[+] Setting $logfile variable in logparser.php to path to your access.log + +[+] Modify logparser.php to match your access log format ( we need parse "ip of request" and "time of request" ), especially time of request must change to match SQLite time format look like 2016-11-05 01:35:24 +Example log line from nginx: +180.93.103.169 - - [05/Nov/2016:03:19:12 +0700] "GET / HTTP/1.0" 200 148608 "-" "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US)" "-" + +[+] Modify analyser.php, setting $threshold as number of request per $timewindow , any ip over this threshold will be +block by iptables + +To get right Threshold for DDoS attacking you, do step below + ++ Use tcpdump to get packets attacking you $ tcpdump -vvvv -i -w ++ Open .pcap file in Wireshark: + + go to Edit -> Preference set: + * "Show burst count for item rather than rate" set Enabled (check mark in the box) + * set Burst rate resolution = Burst rate window size = 60000 miliseconds (1 min) ++ Go Statistic -> ipv4 -> all addresses: burst rate is number of packets per minute, use average numbers (just guess!) to Threshold + +--------- + +$ chmod +x ./xnohatddosfirewall/runddosfirewall.sh + +$ chmod 777 ./xnohatddosfirewall + +Run script with sudo or root privilege: sudo ./runddosfirewall.sh +follow guide on screen + +Press "Ctrl-b d" : to detach tmux + +Re-attach tmux by command $ tmux attach -t 0 + +Start all your services again \ No newline at end of file diff --git a/analyser.php b/analyser.php new file mode 100644 index 0000000..1fba76d --- /dev/null +++ b/analyser.php @@ -0,0 +1,62 @@ +query("PRAGMA synchronous = OFF"); + $db->query("PRAGMA journal_mode = MEMORY"); + $db->query("PRAGMA busy_timeout = 300000"); + + //$res_count_request = $db->query('SELECT remote_ip, count(remote_ip) AS request_num FROM accesslog GROUP BY remote_ip ORDER BY request_num DESC'); //load all request in database is VERY SLOW + $res_count_request = $db->query('SELECT remote_ip, count(remote_ip) AS request_num FROM accesslog WHERE request_time BETWEEN "'.@date("Y-m-d H:i:s", time()-$timewindow).'" AND "'.@date("Y-m-d H:i:s", time()).'" GROUP BY remote_ip ORDER BY request_num DESC'); + while ($row = $res_count_request->fetchArray()) { + //print_r($row); + if($row['request_num'] >= $threshold AND !in_array($row['remote_ip'],$exclude_ips)){ + + exec('iptables -A INPUT -s '.$row['remote_ip'].' -j BLOCKEDIP'); + + echo 'BLOCKED IP: '.$row['remote_ip'].' (REQ_NUM: '.$row['request_num'].")\n"; + file_put_contents('blockedip.log',$row['remote_ip'].'-'.$row['request_num']."\n",FILE_APPEND); + + $ipblocklist[] = $row['remote_ip']; + } + } + + $db->close(); + + echo "SLEEP IN $timewindow seconds\n"; + sleep($timewindow); + +} + +?> \ No newline at end of file diff --git a/logparser.php b/logparser.php new file mode 100644 index 0000000..eb96c5d --- /dev/null +++ b/logparser.php @@ -0,0 +1,63 @@ +query("PRAGMA synchronous = OFF"); +$db->query("PRAGMA journal_mode = MEMORY"); +$db->query("PRAGMA busy_timeout = 300000"); + +//Check log table exist or not +$res_check_table_exist = $db->query("SELECT * FROM sqlite_master WHERE name = 'accesslog' and type='table' "); +if(!$res_check_table_exist->fetchArray()){ // Not have table accesslog + //echo "Table Not exist"; + //Create Table accesslog + $db->exec('CREATE TABLE accesslog (remote_ip varchar(255), request_time NUMERIC)'); + $db->exec("CREATE INDEX accesslog_index ON accesslog(remote_ip,request_time)"); + echo "Table accesslog has been created \r\n"; +} + +//Follow Log +$size = filesize($logfile); //set to current file size to move disk read cursor to end of file +while (true) { + clearstatcache(); + $currentSize = filesize($logfile); + if ($size == $currentSize) { + usleep(100); + continue; + } + + $fh = fopen($logfile, "r"); + fseek($fh, $size); + + while ($line = fgets($fh)) { + + // process the line read. + if($line <> ''){ + //-----Clear wasted character----- + $clear_char = array('[',']'); + $line = str_replace($clear_char,'',$line); //strip special chars + + //-----Parse Log Line----- + $arr_log_line = explode(' ',$line); + //var_dump($arr_log_line);continue; + $remote_ip = $arr_log_line[0]; + $request_time = @date("Y-m-d H:i:s", @strtotime(str_replace('/', '-', substr_replace($arr_log_line[3], ' ', -9,1)))); //original nginx time look like 05/Nov/2016:01:35:24 , remember change for apache , SQLite format must look like 2016-11-05 01:35:24 + $db->exec('INSERT INTO accesslog (remote_ip, request_time) VALUES ("'.$remote_ip.'","'.$request_time.'")'); //insert request to DB + //echo $remote_ip.' - '.$request_time."\r\n"; + echo $line; + } + + } + + fclose($fh); + $size = $currentSize; +} + +$db->close(); + + +?> \ No newline at end of file diff --git a/runddosfirewall.sh b/runddosfirewall.sh new file mode 100644 index 0000000..72c0336 --- /dev/null +++ b/runddosfirewall.sh @@ -0,0 +1,8 @@ +#!/bin/sh +tmux new-session -n 'xnohatDDoSFirewall' -d 'echo -e "Press Ctrl-b LEFT to move Cursor to this panel\nRun Command: php analyser.php"; bash -i' #create window with 1st panel +tmux split-window -h -p 50 'nload; bash -i' #split window horizon to 50% +tmux split-window -v -p 70 'top; bash -i' #split 'new created previous panel' to 2 panel with new create panel is 60% of previous panel +tmux split-window -v -p 40 'php logparser.php; bash -i' #split previous created panel to 2 panel with new create panel is 30% of previous panel +#tmux select-pane -t +1 #move focus to 1st panel +#tmux send-keys 'top; bash -i' Enter #run some command in 1st panel +tmux -2 attach-session -d