📜 ⬆️ ⬇️

Active FreeBSD protection based on logs, sh and cron

Greetings to all FreeBSD administrators!

Having set up my second server on FreeBSD and transferring important corporate information there, I thought about protection. I will not repeat about antiviruses, firewalls and additional useful complexes - none of these tools solved my problem.

The task arose by itself, when viewing logs:
/var/log/exim/rejectlog
/var/log/auth.log
/var/log/apache22/httpd-error.log


they constantly got information about unsuccessful attempts to find the password to exim , to the server, and to webmail, respectively. Sooner or later, attackers can pick up a password, so they need to be somehow stopped, for example, by adding their IP address to the ipfw rules. And on the web server, they also tried to find non-existent directories and files related to administration, such as phpmyadmin, obviously, in order to check them for existing vulnerabilities.

Google and the lissyara article on some aspects of security suggested a direction.
')
The solution in the end looks simple: cron once a minute runs a sh-script that scans the specified logs and adds unlucky violators to the ipfw rules in the form:
deny ip from 123.123.123.123 to me

I managed to modify the lissyara scripts with a file:


For each log file, I made my own sh-script, respectively:
mailsec.sh
nixsec.sh
websec.sh

because they have a slightly different approach to solving the problem, but the general concept is similar.

Scripts consistently work out their electric power, making it almost impossible to brute force and protecting it from being overly curious. According to the accumulated statistics, in a minute the fastest could make no more than 100 attempts at selection. Prior to the commissioning of the scripts, attempts were round-the-clock and innumerable.

I think that such scripts should be on each server, since protection is never enough.
I hope my achievements will help you with this. I give the code. Ready to answer no questions.



mailsec.sh

 #!/bin/sh #  trusted_net='192.168.' debug_log="/var/log/mailsec.log" cur_log_file="rejectlog" cur_log_dir="/var/log/exim/" #echo "Hi!" > /dev/ttyv0 #         if [ `date +%H` -eq 02 ] && [ `date +%M` -eq 04 ] then { #      echo "-= RULES STATS =-" >> ${debug_log} /sbin/ipfw show 3 >> ${debug_log} /sbin/ipfw delete 3 >/dev/null 2>&1 echo "-= RESET RULES =-" >> ${debug_log} date >> ${debug_log} } fi #         cat ${cur_log_dir}${cur_log_file} | grep "auth_login authenticator failed for" | sed 's/ (/--/' | sed 's/failed for--/failed for (/' | sort | awk '{print $1,$8}' | sed 's/\[/ /' | sed 's/\]:/ /' | uniq -c | sort | { while read count_IP do count_deny=`echo ${count_IP} | awk '{print $1}'` logday=`echo ${count_IP} | awk '{print $2}' | cut -d - -f 3` logmonth=`echo ${count_IP} | awk '{print $2}' | cut -d - -f 2` logyear=`echo ${count_IP} | awk '{print $2}' | cut -d - -f 1` IP=`echo ${count_IP} | awk '{print $3}'` day=`date +%d` mon=`date +%m` yea=`date +%Y` ippresent=`/sbin/ipfw show | grep ${IP} >/dev/null 2>&1` if [ ${day} -eq ${logday} ] && [ ${mon} -eq ${logmonth} ] && [ ${yea} -eq ${logyear} ] && [ ! ${ippresent} ] then { if [ ${count_deny} -ge 6 ] && echo $IP | grep ${trusted_net} >/dev/null 2>&1 then echo "MAILSEC: (bruteforce) IP address = ${IP} attempts count = ${count_deny}.    ( IP)" >> ${debug_log} else { if [ ${count_deny} -ge 6 ] then { echo "MAILSEC: (bruteforce) IP address = ${IP} attempts count = ${count_deny}" >> ${debug_log} /sbin/ipfw add 3 deny ip from ${IP} to me >/dev/null 2>&1 } fi } fi } fi done } 




nixsec.sh

 #!/bin/sh #echo "Hi!" > /dev/ttyv0 #        if [ `date +%H` -eq 02 ] && [ `date +%M` -eq 00 ] then { /sbin/ipfw delete 1 >/dev/null 2>&1 echo "-= RESET RULES =-" >> /var/log/nixsec.log date >> /var/log/nixsec.log } fi # day=`date +%d` month=`date +%m` year=`date +%Y` log_dir="/var/old_log/${year}/${month}" #     mkdir -p ${log_dir} log_file="${log_dir}/${day}_auth.log" #   cat /var/log/auth.log > /tmp/auth.log cat /dev/null > /var/log/auth.log cat /tmp/auth.log >> ${log_file} #   IP     #    cat /tmp/auth.log | grep "Invalid user" | awk '{print $10}' | sort | uniq -c | sort | { while read count_IP do count_deny=`echo ${count_IP} | awk '{print $1}'` IP=`echo ${count_IP} | awk '{print $2}'` if [ ${count_deny} -ge 2 ] then { echo "NIXSEC: (invalid user) IP address = ${IP} deny count = ${count_deny}" >> /var/log/nixsec.log /sbin/ipfw add 1 deny ip from ${IP} to me #>/dev/null 2>&1 } fi done } #     cat /tmp/auth.log | grep "Did not receive identification string" | awk '{print $12}' | sort | uniq -c | sort | { while read count_IP do count_deny=`echo ${count_IP} | awk '{print $1}'` IP=`echo ${count_IP} | awk '{print $2}'` if [ ${count_deny} -ge 2 ] then { echo "NIXSEC: (not ident) IP address = ${IP} deny count = ${count_deny}" >> /var/log/nixsec.log /sbin/ipfw add 1 deny ip from ${IP} to me >/dev/null 2>&1 } fi done } #     c   cat /tmp/auth.log | grep "but this does not map back to the address - POSSIBLE BREAK-IN ATTEMPT" | awk '{print $7}' | sort | uniq -c | sort | { while read count_IP do count_deny=`echo ${count_IP} | awk '{print $1}'` IP=`echo ${count_IP} | awk '{print $2}'` if [ ${count_deny} -ge 2 ] then { echo "NIXSEC: (break) IP address = ${IP} deny count = ${count_deny}" >> /var/log/nixsec.log /sbin/ipfw add 1 deny ip from ${IP} to me >/dev/null 2>&1 } fi done } #  ,    root cat /tmp/auth.log | grep "User root from" | awk '{print $9}' | sort | uniq -c | sort | { while read count_IP do count_deny=`echo ${count_IP} | awk '{print $1}'` IP=`echo ${count_IP} | awk '{print $2}'` if [ ${count_deny} -ge 2 ] then { echo "NIXSEC: (root attempt) IP address = ${IP} deny count = ${count_deny}" >> /var/log/nixsec.log /sbin/ipfw add 1 deny ip from ${IP} to me >/dev/null 2>&1 } fi done } 




websec.sh

 #!/bin/sh #  trusted_nets='192.168. 127.0. 10.0.' debug_log="/var/log/websec.log" cur_log_file="httpd-error.log" cur_log_dir="/var/log/apache22" old_log_dir="/var/log/apache22/old" #echo "Hi!" > /dev/ttyv0 #         if [ `date +%H` -eq 02 ] && [ `date +%M` -eq 02 ] then { echo "-= RULES STATS =-" >> ${debug_log} /sbin/ipfw show 2 >> ${debug_log} /sbin/ipfw delete 2 >/dev/null 2>&1 echo "-= RESET RULES =-" >> ${debug_log} date >> ${debug_log} } fi #      day=`date +%d` month=`date +%m` year=`date +%Y` log_dir="${old_log_dir}/${year}/${month}" # Ј    mkdir -p ${log_dir} log_file="${log_dir}/${day}_${cur_log_file}" #   cat ${cur_log_dir}/${cur_log_file} > /tmp/${cur_log_file} #    cat /dev/null > ${cur_log_dir}/${cur_log_file} #    cat /tmp/${cur_log_file} >> ${log_file} #       cat /tmp/${cur_log_file} | grep "File does not exist" | sed 'y/]/ /' | awk '{print $8}' | sort | uniq -c | sort | { while read count_IP do count_deny=`echo ${count_IP} | awk '{print $1}'` IP=`echo ${count_IP} | awk '{print $2}'` if [ ${count_deny} -ge 5 ] && echo $IP | grep 192.168. >/dev/null 2>&1 then echo "WEBSEC: (files) IP address = ${IP} attempts count = ${count_deny}.    ( IP)" >> ${debug_log} else { if [ ${count_deny} -ge 5 ] then { echo "WEBSEC: (files) IP address = ${IP} attempts count = ${count_deny}" >> ${debug_log} /sbin/ipfw add 2 deny ip from ${IP} to me >/dev/null 2>&1 } fi } fi done } #      URI cat /tmp/${cur_log_file} | grep "Invalid URI in request" | sed 'y/]/ /' | awk '{print $8}' | sort | uniq -c | sort | { while read count_IP do count_deny=`echo ${count_IP} | awk '{print $1}'` IP=`echo ${count_IP} | awk '{print $2}'` if [ ${count_deny} -ge 2 ] then { echo "WEBSEC: (URI) IP address = ${IP} attempts count = ${count_deny}" >> ${debug_log} /sbin/ipfw add 2 deny ip from ${IP} to me >/dev/null 2>&1 } fi done } #     RFC cat /tmp/${cur_log_file} | grep "request without hostname" | sed 'y/]/ /' | awk '{print $8}' | sort | uniq -c | sort | { while read count_IP do count_deny=`echo ${count_IP} | awk '{print $1}'` IP=`echo ${count_IP} | awk '{print $2}'` if [ ${count_deny} -ge 2 ] then { echo "WEBSEC: (RFC) IP address = ${IP} attempts count = ${count_deny}" >> ${debug_log} /sbin/ipfw add 2 deny ip from ${IP} to me >/dev/null 2>&1 } fi done } 


Perhaps experts on sh-scripts will be able to help optimize the code.

Source: https://habr.com/ru/post/130501/


All Articles