├── kill_process.py ├── python_plugin_template.txt ├── ip-customblock.sh ├── netsh.cmd ├── LICENSE ├── npf.sh ├── README.md ├── route-null.sh ├── ipfw.sh ├── route-null.cmd ├── ipfw_mac.sh ├── disable-account.sh ├── pf.sh ├── .gitignore ├── host-deny.sh ├── firewalld-drop.sh ├── active_response_extension.py └── firewall-drop.sh /kill_process.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | class Rule(object): 4 | def __init__(self,arguments): 5 | self.arguments = json.loads(arguments) 6 | 7 | def command(self): 8 | return ["kill","-"+str(self.arguments["signal"]),str(self.arguments["pid"])] 9 | 10 | def validate_arguments(self): 11 | """ 12 | :return: 13 | It validates the pid and signal. 14 | """ 15 | return str(self.arguments["pid"]).isdigit() and 1 <= int(self.arguments["signal"]) <= 62 16 | -------------------------------------------------------------------------------- /python_plugin_template.txt: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | class Rule(object): 4 | def __init__(self,arguments): 5 | self.arguments = json.loads(arguments) 6 | 7 | def execute_rule(self): 8 | pass 9 | 10 | def command(self): 11 | """ 12 | Execute some command in python or return os commands for os.PIPE. 13 | :return: 14 | """ 15 | return ["ls"] 16 | 17 | def validate_arguments(self): 18 | """ 19 | :return: 20 | """ 21 | return True 22 | -------------------------------------------------------------------------------- /ip-customblock.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Custom OSSEC block / Easily modifiable for custom responses (touch a file, insert to db, etc). 3 | # Expect: srcip 4 | # Copyright (C) 2015-2020, Wazuh Inc. 5 | # Author: Daniel B. Cid 6 | # Last modified: Feb 16, 2013 7 | 8 | ACTION=$1 9 | USER=$2 10 | IP=$3 11 | 12 | LOCAL=`dirname $0`; 13 | cd $LOCAL 14 | cd ../ 15 | PWD=`pwd` 16 | 17 | 18 | # Logging the call 19 | echo "`date` $0 $1 $2 $3 $4 $5" 20 | 21 | 22 | # IP Address must be provided 23 | if [ "x${IP}" = "x" ]; then 24 | echo "$0: Missing argument (ip)" 25 | exit 1; 26 | fi 27 | 28 | 29 | # Custom block (touching a file inside /ipblock/IP) 30 | if [ "x${ACTION}" = "xadd" ]; then 31 | if [ ! -d /ipblock ]; then 32 | mkdir /ipblock 33 | fi 34 | touch "/ipblock/${IP}" 35 | elif [ "x${ACTION}" = "xdelete" ]; then 36 | rm -f "/ipblock/${IP}" 37 | 38 | # Invalid action 39 | else 40 | echo "$0: invalid action: ${ACTION}" 41 | fi 42 | 43 | exit 1; 44 | -------------------------------------------------------------------------------- /netsh.cmd: -------------------------------------------------------------------------------- 1 | :: Simple script to block an ip using netsh. Commands from http://windowsnerd.com/ 2 | :: Copyright (C) 2015-2020, Wazuh Inc. 3 | @ECHO OFF 4 | ECHO. 5 | 6 | 7 | :: Logging it all 8 | FOR /F "TOKENS=1* DELIMS= " %%A IN ('DATE/T') DO SET DATE=%%B 9 | FOR /F "TOKENS=1* DELIMS= " %%A IN ('TIME/T') DO SET TIME=%%A 10 | ECHO %DATE% %TIME% %0 %1 %2 %3 %4 %5 %6 %7 %8 %9 11 | 12 | 13 | IF "%1"=="add" GOTO ADD 14 | IF "%1"=="delete" GOTO DEL 15 | :ERROR 16 | 17 | ECHO "Invalid argument. %1" 18 | GOTO Exit; 19 | 20 | 21 | :: Adding to the blocked. 22 | 23 | :ADD 24 | :: Extracts last ip address from ipconfig. 25 | netsh ipsec static add policy description="ossec block list" 26 | netsh ipsec static add filter filterlist="ossecfilter" srcaddr=%3 dstaddr=me protocol=tcp mirrored=yes 27 | netsh ipsec static add rule policy="ossec" filterlist="ossecfilter" filteraction="block" desc="list of blocked ips" 28 | netsh ipsec static set policy assign=y 29 | GOTO Exit; 30 | 31 | :DEL 32 | netsh ipsec static delete filter filterlist="ossecfilter" srcaddr=%3 dstaddr=me protocol=tcp mirrored=yes 33 | 34 | :Exit 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 sttor 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /npf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright (C) 2015-2020, Wazuh Inc. 3 | # Author: Gianni D'Aprile 4 | 5 | GREP=`which grep` 6 | 7 | ACTION=$1 8 | USER=$2 9 | IP=$3 10 | 11 | # Finding path 12 | LOCAL=`dirname $0`; 13 | cd $LOCAL 14 | cd ../ 15 | PWD=`pwd` 16 | echo ${PWD} 17 | echo "`date` $0 $1 $2 $3 $4 $5" 18 | 19 | NPFCTL=/sbin/npfctl 20 | 21 | if [ ! -x ${NPFCTL} ]; then 22 | echo "$0: NPF not present." 23 | exit 0; 24 | fi 25 | 26 | NPF_ACTIVE=`${NPFCTL} show | grep "filtering:" | ${GREP} -c active` 27 | 28 | if [ "x1" != "x${NPF_ACTIVE}" ]; then 29 | echo "$0: NPF not active." 30 | exit 0; 31 | fi 32 | 33 | NPF_OSSEC_READY=`${NPFCTL} show | ${GREP} -c "table "` 34 | 35 | if [ "x1" != "x${NPF_OSSEC_READY}" ]; then 36 | echo "$0: NPF not configured." 37 | exit 0; 38 | fi 39 | 40 | # Checking for an IP 41 | if [ "x${IP}" = "x" ]; then 42 | echo "$0: " 43 | exit 1; 44 | fi 45 | 46 | case "x${ACTION}" in 47 | 48 | xadd) 49 | 50 | ${NPFCTL} table ossec_blacklist add ${IP} >/dev/null 2>&1 51 | exit 0 52 | 53 | ;; 54 | 55 | xdelete) 56 | 57 | ${NPFCTL} table ossec_blacklist del ${IP} >/dev/null 2>&1 58 | exit 0 59 | 60 | ;; 61 | 62 | *) 63 | 64 | echo "$0: invalid action: ${ACTION}" 65 | exit 1 66 | 67 | ;; 68 | 69 | esac 70 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Introduction 2 | 3 | Osquery extension to perform active response using sql query. The repo contains 4 | wazuh active response .sh and .cmd files and some python scripts. 5 | Custom .sh,.cmd and .py can be added and hence can be remotely used by osquery. The 6 | extension is coded keeping security in mind. 7 | 8 | The core is just few lines of python codes. 9 | 10 | ## Execution 11 | 12 | * `pip install osquery` 13 | * `chmod +x active_response_extension.py` 14 | * `sudo osqueryi --allow_unsafe --extension active_response_extension.py` 15 | 16 | 17 | > Executing Wazuh responses 18 | 19 | select * from active_response where rule="host-deny.sh" and action="add" and ip="24.56.78.98"'; 20 | 21 | > Killing a process 22 | 23 | select * from active_response where rule="kill_process" and args='{"signal":"9","pid":56776}'; 24 | 25 | 26 | Wazuh require action,ip,user in order to execute the command. 27 | 28 | > Create your own command in python. 29 | 30 | 1. Refer kill_process.py structure 31 | 2. import the custom file 32 | 3. include filename in ActiveResonse.PYTHON_RULES. 33 | 4. In query add **args** as a json of arguments required. 34 | 35 | Read more about it on [docs](https://docs.easysiem.com/agents/osquery/active-response-extensions) 36 | 37 | 38 | 39 | ## TODO 40 | 41 | -------------------------------------------------------------------------------- /route-null.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Adds an IP to null route 3 | # Requirements: ip route 4 | # Expect: srcip 5 | # Copyright (C) 2015-2020, Wazuh Inc. 6 | # Author: Ivan Lotina 7 | # Modifyed script host-deny from Daniel B. Cid 8 | # Last modified: Feb 16, 2007 9 | 10 | ACTION=$1 11 | USER=$2 12 | IP=$3 13 | 14 | LOCAL=`dirname $0`; 15 | cd $LOCAL 16 | cd ../ 17 | PWD=`pwd` 18 | LOCK="${PWD}/host-deny-lock" 19 | LOCK_PID="${PWD}/host-deny-lock/pid" 20 | 21 | UNAME=`uname` 22 | 23 | # Logging the call 24 | echo "`date` $0 $1 $2 $3 $4 $5" 25 | 26 | 27 | # IP Address must be provided 28 | if [ "x${IP}" = "x" ]; then 29 | echo "$0: Missing argument (ip)" 30 | exit 1; 31 | fi 32 | 33 | 34 | # Adding the ip to null route 35 | if [ "x${ACTION}" = "xadd" ]; then 36 | if [ "X${UNAME}" = "XLinux" ]; then 37 | route add ${IP} reject 38 | exit 0; 39 | fi 40 | 41 | if [ "X${UNAME}" = "XFreeBSD" ]; then 42 | route -q add ${IP} 127.0.0.1 -blackhole 43 | exit 0; 44 | fi 45 | 46 | # Deleting from null route 47 | # be carefull not to remove your default route 48 | elif [ "x${ACTION}" = "xdelete" ]; then 49 | if [ "X${UNAME}" = "XLinux" ]; then 50 | route del ${IP} reject 51 | exit 0; 52 | fi 53 | 54 | if [ "X${UNAME}" = "XFreeBSD" ]; then 55 | route -q delete ${IP} 127.0.0.1 -blackhole 56 | exit 0; 57 | fi 58 | 59 | # Invalid action 60 | else 61 | echo "$0: invalid action: ${ACTION}" 62 | fi 63 | 64 | exit 1; 65 | -------------------------------------------------------------------------------- /ipfw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Adds an IP to the IPFW drop list. 3 | # Only works with IPFW. 4 | # We use TABLE 00001. If you use this table for anything else, 5 | # please change it here. 6 | # Expect: srcip 7 | # Copyright (C) 2015-2020, Wazuh Inc. 8 | # Author: Rafael Capovilla - under @ ( at ) underlinux.com.br 9 | # Author: Daniel B. Cid - dcid @ ( at ) ossec.net 10 | # Last modified: May 07, 2006 11 | 12 | UNAME=`uname` 13 | IPFW="/sbin/ipfw" 14 | ARG1="" 15 | ARG2="" 16 | ACTION=$1 17 | USER=$2 18 | IP=$3 19 | TABLE_ID=00001 20 | 21 | LOCAL=`dirname $0`; 22 | cd $LOCAL 23 | cd ../ 24 | PWD=`pwd` 25 | echo "`date` $0 $1 $2 $3 $4 $5" 26 | 27 | 28 | # Checking for an IP 29 | if [ "x${IP}" = "x" ]; then 30 | echo "$0: " 31 | exit 1; 32 | fi 33 | 34 | 35 | 36 | # Blocking IP 37 | if [ "x${ACTION}" != "xadd" -a "x${ACTION}" != "xdelete" ]; then 38 | echo "$0: Invalid action: ${ACTION}" 39 | exit 1; 40 | fi 41 | 42 | 43 | # We should run on FreeBSD 44 | # We always use table 00001 and rule id 00001. 45 | if [ "X${UNAME}" = "XFreeBSD" ]; then 46 | ls ${IPFW} >> /dev/null 2>&1 47 | if [ $? != 0 ]; then 48 | exit 0; 49 | fi 50 | 51 | # Check if our table is set 52 | ${IPFW} show | grep "^00001" | grep "table(1)" >/dev/null 2>&1 53 | if [ ! $? = 0 ]; then 54 | # We need to add the table 55 | ${IPFW} -q 00001 add deny ip from table\(${TABLE_ID}\) to any 56 | ${IPFW} -q 00001 add deny ip from any to table\(${TABLE_ID}\) 57 | fi 58 | 59 | 60 | # Executing and exiting 61 | ${IPFW} -q table ${TABLE_ID} ${ACTION} ${IP} 62 | 63 | exit 0; 64 | fi 65 | 66 | 67 | # Not FreeBSD 68 | exit 1; 69 | -------------------------------------------------------------------------------- /route-null.cmd: -------------------------------------------------------------------------------- 1 | :: Script to null route an ip address. 2 | :: Copyright (C) 2015-2020, Wazuh Inc. 3 | @ECHO OFF 4 | ECHO. 5 | 6 | :: Set some variables 7 | FOR /F "TOKENS=1* DELIMS= " %%A IN ('DATE/T') DO SET DATE=%%A %%B 8 | FOR /F "TOKENS=1-3 DELIMS=:" %%A IN ("%TIME%") DO SET TIME=%%A:%%B:%%C 9 | SET IP_REGEX="[0-9][0-9]*[0-9]*\.[0-9][0-9]*[0-9]*\.[0-9][0-9]*[0-9]*\.[0-9][0-9]*[0-9]*" 10 | 11 | :: Check for required arguments 12 | IF /I "%1"=="" GOTO ERROR 13 | IF /I "%1"=="add" GOTO ADD 14 | IF /I "%1"=="delete" GOTO DEL 15 | 16 | :ERROR 17 | ECHO Invalid argument(s). 18 | ECHO Usage: route-null.cmd ^(ADD^|DELETE^) - IPv4 Address 19 | ECHO Example: route-null.cmd ADD - 1.2.3.4 20 | ECHO Example: route-null.cmd DELETE - 1.2.3.4 21 | EXIT /B 1 22 | 23 | :ADD 24 | :: Check for a valid IP 25 | ECHO "%3" | %WINDIR%\system32\findstr.exe /R %IP_REGEX% >nul || ECHO Invalid IP && EXIT /B 2 26 | :: Extracts last ip address from ipconfig and routes to this address. Windows will not allow routing to 127.0.0.1 27 | FOR /F "TOKENS=2* DELIMS=:" %%A IN ('%WINDIR%\system32\ipconfig.exe ^| %WINDIR%\system32\findstr.exe /R /C:".*IP.*[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*"') DO FOR %%B IN (%%A) DO SET IPADDR=%%B 28 | :: Adding IP to be null-routed. IP will be routed to local machine IP 29 | %WINDIR%\system32\route.exe -p ADD %3 MASK 255.255.255.255 %IPADDR% 30 | GOTO LOG 31 | 32 | :DEL 33 | :: Check for a valid IP 34 | ECHO "%3" | %WINDIR%\system32\findstr.exe /R %IP_REGEX% >nul || ECHO Invalid IP && EXIT /B 2 35 | :: Deleting IP 36 | %WINDIR%\system32\route.exe DELETE %3 37 | GOTO LOG 38 | 39 | :LOG 40 | ECHO %DATE%%TIME% %0 %1 %2 %3 %4 %5 %6 %7 %8 %9 41 | GOTO EXIT 42 | 43 | :EXIT /B 0: 44 | -------------------------------------------------------------------------------- /ipfw_mac.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Adds an IP to the IPFW drop list. 3 | # Only works with IPFW. 4 | # Expect: srcip 5 | # Copyright (C) 2015-2020, Wazuh Inc. 6 | # Author: Rafael Capovilla - under @ ( at ) underlinux.com.br 7 | # Author: Daniel B. Cid - dcid @ ( at ) ossec.net 8 | # Author: Charles W. Kefauver ckefauver @ ( at ) ibacom.es 9 | # changed for Mac OS X compatibility 10 | 11 | UNAME=`uname` 12 | IPFW="/sbin/ipfw" 13 | ARG1="" 14 | ARG2="" 15 | ACTION=$1 16 | USER=$2 17 | IP=$3 18 | 19 | # warning do NOT add leading 0 in SET_ID 20 | SET_ID=2 21 | 22 | LOCAL=`dirname $0`; 23 | cd $LOCAL 24 | cd ../ 25 | PWD=`pwd` 26 | echo "`date` $0 $1 $2 $3 $4 $5" 27 | 28 | 29 | # Checking for an IP 30 | if [ "x${IP}" = "x" ]; then 31 | echo "$0: " 32 | exit 1; 33 | fi 34 | 35 | # Blocking IP 36 | if [ "x${ACTION}" != "xadd" -a "x${ACTION}" != "xdelete" ]; then 37 | echo "$0: Invalid action: ${ACTION}" 38 | exit 1; 39 | fi 40 | 41 | 42 | # We should run on Darwin 43 | if [ "X${UNAME}" = "XDarwin" ]; then 44 | ls ${IPFW} >> /dev/null 2>&1 45 | if [ $? != 0 ]; then 46 | exit 0; 47 | fi 48 | 49 | 50 | # Executing and exiting 51 | if [ "x${ACTION}" = "xadd" ]; then 52 | #${IPFW} set disable ${SET_ID} 53 | ${IPFW} -q add set ${SET_ID} deny ip from ${IP} to any 54 | ${IPFW} -q add set ${SET_ID} deny ip from any to ${IP} 55 | ${IPFW} -q set enable ${SET_ID} 56 | exit 0; 57 | fi 58 | 59 | if [ "x${ACTION}" = "xdelete" ]; then 60 | #${IPFW} -S show | grep "set ${SET_ID}" | grep "${IP}" >/dev/null 2>&1 61 | #get list of ipfw rules ID to delete 62 | RULES_TO_DELETE=`${IPFW} -S show | grep "set ${SET_ID}" | grep "${IP}" | awk '{print $1}'` 63 | 64 | for RULE_ID in ${RULES_TO_DELETE} 65 | do 66 | ${IPFW} -q delete ${RULE_ID} 67 | done 68 | 69 | exit 0; 70 | fi 71 | 72 | exit 0; 73 | fi 74 | 75 | 76 | # Not Darwin 77 | exit 1; 78 | 79 | -------------------------------------------------------------------------------- /disable-account.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Disable an account by setting "passwd -l" or chuser 3 | # Requirements: System with a passwd that supports -l and -u 4 | # or a system with chuser (AIX) 5 | # Expect: username (can't be "root") 6 | # Copyright (C) 2015-2020, Wazuh Inc. 7 | # Authors: Ahmet Ozturk and Daniel B. Cid 8 | # Last modified: Jan 19, 2005 9 | 10 | 11 | UNAME=`uname` 12 | PASSWD="/usr/bin/passwd" 13 | CHUSER="/usr/bin/chuser" 14 | ACTION=$1 15 | USER=$2 16 | IP=$3 17 | 18 | LOCAL=`dirname $0`; 19 | cd $LOCAL 20 | cd ../ 21 | PWD=`pwd` 22 | echo "`date` $0 $1 $2 $3 $4 $5" 23 | 24 | 25 | if [ "x${USER}" = "x" ]; then 26 | echo "$0: [ add | delete ] " 27 | exit 1; 28 | elif [ "x${USER}" = "xroot" ]; then 29 | echo "$0: Invalid username." 30 | exit 1; 31 | fi 32 | 33 | 34 | # We should run on linux and on SunOS the passwd -u/-l 35 | if [ "X${UNAME}" = "XLinux" -o "X${UNAME}" = "XSunOS" ]; then 36 | # Checking if passwd is present 37 | ls ${PASSWD} >> /dev/null 2>&1 38 | if [ $? != 0 ]; then 39 | exit 0; 40 | fi 41 | 42 | CMD=${PASSWD} 43 | if [ "x${ACTION}" = "xadd" ]; then 44 | ARGS="-l" 45 | elif [ "x${ACTION}" = "xdelete" ]; then 46 | ARGS="-u" 47 | else 48 | echo "$0: invalid action: ${ACTION}" 49 | exit 1; 50 | fi 51 | 52 | 53 | # On AIX, we run CHUSER 54 | elif [ "X${UNAME}" = "XAIX" ]; then 55 | # Checking if chuser is present 56 | ls ${CHUSER} >> /dev/null 2>&1 57 | if [ $? != 0 ]; then 58 | exit 0; 59 | fi 60 | 61 | CMD=${CHUSER} 62 | 63 | # Disabling an account 64 | if [ "x${ACTION}" = "xadd" ]; then 65 | ARGS="account_locked=true" 66 | # Unblock the account 67 | elif [ "x${ACTION}" = "xdelete" ]; then 68 | ARGS="account_locked=false" 69 | # Invalid action 70 | else 71 | echo "$0: invalid action: ${ACTION}" 72 | exit 1; 73 | fi 74 | 75 | 76 | # We only support Linux, SunOS and AIX 77 | else 78 | exit 0; 79 | fi 80 | 81 | 82 | # Execute the command 83 | ${CMD} ${ARGS} ${USER} 84 | 85 | exit 1; 86 | 87 | -------------------------------------------------------------------------------- /pf.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Copyright (C) 2015-2020, Wazuh Inc. 3 | # Author: Rafael M. Capovilla 4 | # Last modified: Daniel B. Cid 5 | 6 | UNAME=`uname` 7 | GREP="/usr/bin/grep" 8 | PFCTL="/sbin/pfctl" 9 | PFCTL_RULES="/etc/pf.conf" 10 | PFCTL_TABLE="ossec_fwtable" 11 | ARG1="" 12 | ARG2="" 13 | CHECKTABLE="" 14 | ACTION=$1 15 | USER=$2 16 | IP=$3 17 | 18 | # Getting pf rules file. 19 | if [ ! -f $PFCTL_RULES ]; then 20 | echo "The pf rules file $PFCTL_RULES does not exist" 21 | exit 1 22 | fi 23 | 24 | # Checking if ossec table is configured 25 | CHECKTABLE=`cat ${PFCTL_RULES} | $GREP $PFCTL_TABLE` 26 | if [ -z "$CHECKTABLE" ]; then 27 | echo "Table $PFCTL_TABLE does not exist" 28 | exit 1 29 | fi 30 | 31 | # Finding path 32 | LOCAL=`dirname $0`; 33 | cd $LOCAL 34 | cd ../ 35 | PWD=`pwd` 36 | echo "`date` $0 $1 $2 $3 $4 $5" 37 | 38 | # Checking for an IP 39 | if [ "x${IP}" = "x" ]; then 40 | echo "$0: " 41 | exit 1; 42 | fi 43 | 44 | # Blocking IP 45 | if [ "x${ACTION}" != "xadd" -a "x${ACTION}" != "xdelete" ]; then 46 | echo "$0: invalid action: ${ACTION}" 47 | exit 1; 48 | fi 49 | 50 | # OpenBSD and FreeBSD pf 51 | if [ "X${UNAME}" = "XOpenBSD" -o "X${UNAME}" = "XFreeBSD" -o "X${UNAME}" = "XDarwin" ]; then 52 | 53 | # Checking if pfctl is present 54 | ls ${PFCTL} > /dev/null 2>&1 55 | if [ ! $? = 0 ]; then 56 | echo "$0: PF not configured." 57 | exit 0; 58 | fi 59 | 60 | # Checking if we have pf config file 61 | if [ -e ${PFCTL_RULES} ]; then 62 | 63 | #Checking if we got the table to add the bad guys 64 | if [ "x${PFCTL_TABLE}" = "x" ]; then 65 | echo "$0: PF not configured." 66 | exit 0; 67 | else 68 | if [ "x${ACTION}" = "xadd" ]; then 69 | ARG1="-t $PFCTL_TABLE -T add ${IP}" 70 | ARG2="-k ${IP}" 71 | else 72 | ARG1="-t $PFCTL_TABLE -T delete ${IP}" 73 | fi 74 | fi 75 | else 76 | exit 0; 77 | fi 78 | 79 | #Executing it 80 | ${PFCTL} ${ARG1} > /dev/null 2>&1 81 | ${PFCTL} ${ARG2} > /dev/null 2>&1 82 | exit 0; 83 | 84 | else 85 | exit 0; 86 | fi 87 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | 131 | #editor 132 | 133 | .idea/ -------------------------------------------------------------------------------- /host-deny.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Adds an IP to the /etc/hosts.deny file 3 | # Requirements: sshd and other binaries with tcp wrappers support 4 | # Expect: srcip 5 | # Copyright (C) 2015-2020, Wazuh Inc. 6 | # Author: Daniel B. Cid 7 | # Last modified: Nov 09, 2005 8 | 9 | ACTION=$1 10 | USER=$2 11 | IP=$3 12 | 13 | LOCAL=`dirname $0`; 14 | cd $LOCAL 15 | cd ../ 16 | PWD=`pwd` 17 | LOCK="${PWD}/host-deny-lock" 18 | LOCK_PID="${PWD}/host-deny-lock/pid" 19 | UNAME=`uname` 20 | 21 | 22 | # This number should be more than enough (even if a hundred 23 | # instances of this script is ran together). If you have 24 | # a really loaded env, you can increase it to 75 or 100. 25 | MAX_ITERATION="50" 26 | 27 | 28 | # Lock function 29 | lock() 30 | { 31 | i=0; 32 | # Providing a lock. 33 | while [ 1 ]; do 34 | mkdir ${LOCK} > /dev/null 2>&1 35 | MSL=$? 36 | if [ "${MSL}" = "0" ]; then 37 | # Lock acquired (setting the pid) 38 | echo "$$" > ${LOCK_PID} 39 | return; 40 | fi 41 | 42 | # Getting currently/saved PID locking the file 43 | C_PID=`cat ${LOCK_PID} 2>/dev/null` 44 | if [ "x" = "x${S_PID}" ]; then 45 | S_PID=${C_PID} 46 | fi 47 | 48 | # Breaking out of the loop after X attempts 49 | if [ "x${C_PID}" = "x${S_PID}" ]; then 50 | i=`expr $i + 1`; 51 | fi 52 | 53 | sleep $i; 54 | 55 | i=`expr $i + 1`; 56 | 57 | # So i increments 2 by 2 if the pid does not change. 58 | # If the pid keeps changing, we will increments one 59 | # by one and fail after MAX_ITERACTION 60 | if [ "$i" = "${MAX_ITERATION}" ]; then 61 | echo "`date` Unable to execute. Locked: $0" 62 | 63 | # Unlocking and exiting 64 | unlock; 65 | exit 1; 66 | fi 67 | done 68 | } 69 | 70 | # Unlock function 71 | unlock() 72 | { 73 | rm -rf ${LOCK} 74 | } 75 | 76 | 77 | # Logging the call 78 | echo "`date` $0 $1 $2 $3 $4 $5" 79 | 80 | 81 | # IP Address must be provided 82 | if [ "x${IP}" = "x" ]; then 83 | echo "$0: Missing argument (ip)" 84 | exit 1; 85 | fi 86 | 87 | 88 | # Checking for invalid entries (lacking "." or ":", etc) 89 | echo "${IP}" | egrep "\.|\:" > /dev/null 2>&1 90 | if [ ! $? = 0 ]; then 91 | echo "`date` Invalid ip/hostname entry: ${IP}" 92 | exit 1; 93 | fi 94 | 95 | 96 | # Adding the ip to hosts.deny 97 | if [ "x${ACTION}" = "xadd" ]; then 98 | # Looking for duplication 99 | IPKEY=$(grep -w "${IP}" /etc/hosts.deny) 100 | if [ ! -z "$IPKEY" ]; then 101 | echo "IP ${IP} already exists on host.deny..." 102 | exit 1 103 | fi 104 | lock; 105 | echo "${IP}" | grep "\:" > /dev/null 2>&1 106 | if [ $? = 0 ]; then 107 | IP="[${IP}]" 108 | fi 109 | if [ "X$UNAME" = "XFreeBSD" ]; then 110 | echo "ALL : ${IP} : deny" >> /etc/hosts.allow 111 | else 112 | echo "ALL:${IP}" >> /etc/hosts.deny 113 | fi 114 | unlock; 115 | exit 0; 116 | 117 | 118 | # Deleting from hosts.deny 119 | elif [ "x${ACTION}" = "xdelete" ]; then 120 | lock; 121 | TMP_FILE=`mktemp ${PWD}/ossec-hosts.XXXXXXXXXX` 122 | if [ "X${TMP_FILE}" = "X" ]; then 123 | # Cheap fake tmpfile, but should be harder then no random data 124 | TMP_FILE="${PWD}/ossec-hosts.`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -1 `" 125 | fi 126 | echo "${IP}" | grep "\:" > /dev/null 2>&1 127 | if [ $? = 0 ]; then 128 | IP="\[${IP}\]" 129 | fi 130 | if [ "X$UNAME" = "XFreeBSD" ]; then 131 | cat /etc/hosts.allow | grep -v "ALL : ${IP} : deny$"> ${TMP_FILE} 132 | mv ${TMP_FILE} /etc/hosts.allow 133 | else 134 | cat /etc/hosts.deny | grep -v "ALL:${IP}$"> ${TMP_FILE} 135 | cat ${TMP_FILE} > /etc/hosts.deny 136 | rm ${TMP_FILE} 137 | fi 138 | unlock; 139 | exit 0; 140 | 141 | 142 | # Invalid action 143 | else 144 | echo "$0: invalid action: ${ACTION}" 145 | fi 146 | 147 | exit 1; 148 | -------------------------------------------------------------------------------- /firewalld-drop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Adds an IP to the firewalld drop list 3 | # Requirements: Linux with firewalld 4 | # Expect: srcip 5 | # Copyright (C) 2015-2020, Wazuh Inc. 6 | # Author: Daniel B. Cid (iptables) 7 | # Author: cgzones 8 | # Author: ChristianBeer 9 | # Last modified: Apr 10, 2015 10 | 11 | UNAME=`uname` 12 | ECHO="/bin/echo" 13 | GREP="/bin/grep" 14 | FWDCMD="/bin/firewall-cmd" 15 | RULE="" 16 | ARG1="" 17 | # ARG2 can be used to specify the zone where the rich rule should be added otherwise it adds it to the default zone 18 | ARG2="" 19 | #ARG2="--zone=external" 20 | RULEID="" 21 | ACTION=$1 22 | USER=$2 23 | IP=$3 24 | PWD=`pwd` 25 | LOCK="${PWD}/fw-drop" 26 | LOCK_PID="${PWD}/fw-drop/pid" 27 | 28 | 29 | LOCAL=`dirname $0`; 30 | cd $LOCAL 31 | cd ../ 32 | filename=$(basename "$0") 33 | 34 | echo "`date` $0 $1 $2 $3 $4 $5" 35 | 36 | 37 | # Checking for an IP 38 | if [ "x${IP}" = "x" ]; then 39 | echo "$0: " 40 | exit 1; 41 | fi 42 | 43 | case "${IP}" in 44 | *:* ) RULE="rule family='ipv6' source address='${IP}' drop";; 45 | *.* ) RULE="rule family='ipv4' source address='${IP}' drop";; 46 | * ) echo "`date` Unable to run active response (invalid IP: '${IP}')." && exit 1;; 47 | esac 48 | 49 | # This number should be more than enough (even if a hundred 50 | # instances of this script is ran together). If you have 51 | # a really loaded env, you can increase it to 75 or 100. 52 | MAX_ITERATION="50" 53 | 54 | # Lock function 55 | lock() 56 | { 57 | i=0; 58 | # Providing a lock. 59 | while [ 1 ]; do 60 | mkdir ${LOCK} > /dev/null 2>&1 61 | MSL=$? 62 | if [ "${MSL}" = "0" ]; then 63 | # Lock acquired (setting the pid) 64 | echo "$$" > ${LOCK_PID} 65 | return; 66 | fi 67 | 68 | # Getting currently/saved PID locking the file 69 | C_PID=`cat ${LOCK_PID} 2>/dev/null` 70 | if [ "x" = "x${S_PID}" ]; then 71 | S_PID=${C_PID} 72 | fi 73 | 74 | # Breaking out of the loop after X attempts 75 | if [ "x${C_PID}" = "x${S_PID}" ]; then 76 | i=`expr $i + 1`; 77 | fi 78 | 79 | sleep $i; 80 | 81 | i=`expr $i + 1`; 82 | 83 | # So i increments 2 by 2 if the pid does not change. 84 | # If the pid keeps changing, we will increments one 85 | # by one and fail after MAX_ITERACTION 86 | 87 | if [ "$i" = "${MAX_ITERATION}" ]; then 88 | kill="false" 89 | for pid in `pgrep -f "${filename}"`; do 90 | if [ "x${pid}" = "x${C_PID}" ]; then 91 | # Unlocking and exiting 92 | kill -9 ${C_PID} 93 | echo "`date` Killed process ${C_PID} holding lock." 94 | kill="true" 95 | unlock; 96 | i=0; 97 | S_PID=""; 98 | break; 99 | fi 100 | done 101 | 102 | if [ "x${kill}" = "xfalse" ]; then 103 | echo "`date` Unable kill process ${C_PID} holding lock." 104 | # Unlocking and exiting 105 | unlock; 106 | exit 1; 107 | fi 108 | fi 109 | done 110 | } 111 | 112 | # Unlock function 113 | unlock() 114 | { 115 | rm -rf ${LOCK} 116 | } 117 | 118 | 119 | 120 | # Blocking IP 121 | if [ "x${ACTION}" != "xadd" -a "x${ACTION}" != "xdelete" ]; then 122 | echo "$0: invalid action: ${ACTION}" 123 | exit 1; 124 | fi 125 | 126 | 127 | 128 | # We should run on linux 129 | if [ "X${UNAME}" = "XLinux" ]; then 130 | if [ "x${ACTION}" = "xadd" ]; then 131 | ARG1="--add-rich-rule=" 132 | else 133 | ARG1="--remove-rich-rule=" 134 | fi 135 | 136 | # Checking if firewall-cmd is present 137 | if [ ! -x ${FWDCMD} ]; then 138 | FWDCMD="/usr"${FWDCMD} 139 | if [ ! -x ${FWDCMD} ]; then 140 | echo "$0: can not find firewall-cmd" 141 | exit 1; 142 | fi 143 | fi 144 | 145 | # Executing and exiting 146 | COUNT=0; 147 | lock; 148 | while [ 1 ]; do 149 | ${FWDCMD} ${ARG1}"${RULE}" ${ARG2} >/dev/null 150 | RES=$? 151 | if [ $RES = 0 ]; then 152 | break; 153 | else 154 | COUNT=`expr $COUNT + 1`; 155 | echo "`date` Unable to run (firewall-cmd returning != $RES): $COUNT - $0 $1 $2 $3 $4 $5" 156 | sleep $COUNT; 157 | 158 | if [ $COUNT -gt 4 ]; then 159 | break; 160 | fi 161 | fi 162 | done 163 | unlock; 164 | 165 | exit 0; 166 | else 167 | exit 0; 168 | fi 169 | -------------------------------------------------------------------------------- /active_response_extension.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import json 4 | import os 5 | import re 6 | import subprocess 7 | import sys 8 | import traceback 9 | 10 | import osquery 11 | 12 | @osquery.register_plugin 13 | class ActiveResponsePlugin(osquery.TablePlugin): 14 | """ 15 | Plugin to perform action on machine. 16 | """ 17 | 18 | def name(self): 19 | return "active_response" 20 | 21 | def columns(self): 22 | """ 23 | :return: 24 | stdout will return stdout message. 25 | stderr will return stderr message 26 | action can be "iptable_rule" or "process_kill" 27 | arguments are the command line arguments passed from clients. 28 | """ 29 | return [ 30 | osquery.TableColumn(name="action", type=osquery.STRING), 31 | osquery.TableColumn(name="args", type=osquery.STRING), 32 | osquery.TableColumn(name="rule", type=osquery.STRING), 33 | osquery.TableColumn(name="user", type=osquery.STRING), 34 | osquery.TableColumn(name="ip", type=osquery.STRING), 35 | osquery.TableColumn(name="stdout", type=osquery.STRING), 36 | osquery.TableColumn(name="stderr", type=osquery.STRING), 37 | ] 38 | 39 | def get_context_list_val(self, val): 40 | return "" if not val else val[0]["expr"] 41 | 42 | def generate(self, context): 43 | """ 44 | :param context: 45 | :return: 46 | It will parse the context's arguments and will fetch user supplied info to be executed on machine. 47 | """ 48 | cmd_lines = map(lambda x: (x["name"], self.get_context_list_val(x['list'])), 49 | json.loads(json.loads(context))["constraints"]) 50 | row = dict(cmd_lines) 51 | stdout, stderr = self.process_and_run_cmd(row) 52 | row['stdout'] = stdout 53 | row['stderr'] = stderr 54 | return [row] 55 | 56 | def process_and_run_cmd(self, cmd_dict): 57 | try: 58 | return ActiveResponse(cmd_dict).respond() 59 | except (AttributeError, ValueError, TypeError) as e: 60 | return "", str(e) 61 | 62 | 63 | class ActiveResponse(object): 64 | """ 65 | Entry point of the executeion that will call the required actions. 66 | Add any new Rule file here. Default is the active response rule files from wazuh-response 67 | """ 68 | WAZUH_RULES = [ 69 | 'route-null.sh', 70 | 'ip-customblock.sh', 71 | 'firewall-drop.sh', 72 | 'host-deny.sh', 73 | 'ipfw_mac.sh', 74 | 'npf.sh', 75 | 'ipfw.sh', 76 | 'pf.sh', 77 | 'route-null.cmd', 78 | 'disable-account.sh', 79 | 'firewalld-drop.sh', 80 | ] 81 | 82 | PYTHON_RULE = [ 83 | 'kill_process' 84 | ] 85 | 86 | BASH_RULE = [ 87 | 88 | ] 89 | 90 | def __init__(self, cmd_dict): 91 | self.cmd_dict = cmd_dict 92 | self.rule = self.cmd_dict["rule"] 93 | self.action = self.cmd_dict.get("action", "-") or "-" 94 | self.user = self.cmd_dict.get("user", "-") or "-" 95 | self.ip = self.cmd_dict.get("ip", "-") or "-" 96 | self.args = self.cmd_dict.get("args", "") or "" 97 | 98 | def rule_obj(self): 99 | module = sys.modules.get(self.rule) 100 | return getattr(module, "Rule")(self.args) 101 | 102 | def is_ip_valid(self,IP): 103 | def isIPv4(s): 104 | try: 105 | return str(int(s)) == s and 0 <= int(s) <= 255 106 | except: 107 | return False 108 | 109 | def isIPv6(s): 110 | if len(s) > 4: 111 | return False 112 | try: 113 | return int(s, 16) >= 0 and s[0] != '-' 114 | except: 115 | return False 116 | 117 | if IP.count(".") == 3 and all(isIPv4(i) for i in IP.split(".")): 118 | return True 119 | if IP.count(":") == 7 and all(isIPv6(i) for i in IP.split(":")): 120 | return True 121 | return False 122 | 123 | 124 | def validate_arguments(self): 125 | assert self.ip == "-" or self.is_ip_valid(self.ip) 126 | assert self.action in ["-", "add", "delete"] 127 | assert self.user == "-" or re.match("^[a-zA-Z0-9_.-]+$", self.user) 128 | assert self.rule in ActiveResponse.WAZUH_RULES + ActiveResponse.PYTHON_RULE + ActiveResponse.BASH_RULE 129 | if self.rule in ActiveResponse.PYTHON_RULE: 130 | assert self.rule_obj().validate_arguments() 131 | 132 | def build_command(self): 133 | command = [self.rule, self.action, self.user, self.ip] 134 | if self.rule in ActiveResponse.PYTHON_RULE: 135 | command = self.rule_obj().command() 136 | elif ".cmd" in self.rule: 137 | command[0]="C:\\Program Files\\osquery\\extensions\\" + self.rule 138 | else: 139 | command[0] = os.path.join(os.path.dirname(os.path.abspath(__file__)),self.rule) 140 | return command 141 | 142 | def respond(self): 143 | out, err = ("", "") 144 | try: 145 | self.validate_arguments() 146 | command = self.build_command() 147 | p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 148 | out, err = p.communicate() 149 | except Exception as e: 150 | _, _, tb = sys.exc_info() 151 | #traceback.print_tb(tb) # Fixed format 152 | tb_info = traceback.extract_tb(tb) 153 | filename, line, func, text = tb_info[-1] 154 | err = 'An error occurred on line {} in statement {} - {}'.format(line, text, str(e)) 155 | 156 | return [out, err] 157 | 158 | 159 | if __name__ == "__main__": 160 | osquery.start_extension(name="active_response", version="1.0.0") -------------------------------------------------------------------------------- /firewall-drop.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # Adds an IP to the iptables drop list (if linux) 3 | # Adds an IP to the ipfilter drop list (if solaris, freebsd or netbsd) 4 | # Adds an IP to the ipsec drop list (if aix) 5 | # Requirements: Linux with iptables, Solaris/FreeBSD/NetBSD with ipfilter or AIX with IPSec 6 | # Expect: srcip 7 | # Copyright (C) 2015-2020, Wazuh Inc. 8 | # Author: Ahmet Ozturk (ipfilter and IPSec) 9 | # Author: Daniel B. Cid (iptables) 10 | # Author: cgzones 11 | 12 | UNAME=`uname` 13 | ECHO="/bin/echo" 14 | GREP="/bin/grep" 15 | IPTABLES="" 16 | IP4TABLES="/sbin/iptables" 17 | IP6TABLES="/sbin/ip6tables" 18 | IPFILTER="/sbin/ipf" 19 | if [ "X$UNAME" = "XSunOS" ]; then 20 | IPFILTER="/usr/sbin/ipf" 21 | fi 22 | GENFILT="/usr/sbin/genfilt" 23 | LSFILT="/usr/sbin/lsfilt" 24 | MKFILT="/usr/sbin/mkfilt" 25 | RMFILT="/usr/sbin/rmfilt" 26 | ARG1="" 27 | ARG2="" 28 | RULEID="" 29 | ACTION=$1 30 | USER=$2 31 | IP=$3 32 | PWD=`pwd` 33 | LOCK="${PWD}/fw-drop" 34 | LOCK_PID="${PWD}/fw-drop/pid" 35 | 36 | 37 | LOCAL=`dirname $0`; 38 | cd $LOCAL 39 | cd ../ 40 | filename=$(basename "$0") 41 | 42 | echo "`date` $0 $1 $2 $3 $4 $5" 43 | 44 | 45 | # Checking for an IP 46 | if [ "x${IP}" = "x" ]; then 47 | echo "$0: " 48 | exit 1; 49 | fi 50 | 51 | case "${IP}" in 52 | *:* ) IPTABLES=$IP6TABLES;; 53 | *.* ) IPTABLES=$IP4TABLES;; 54 | * ) echo "`date` Unable to run active response (invalid IP: '${IP}')." && exit 1;; 55 | esac 56 | 57 | # This number should be more than enough (even if a hundred 58 | # instances of this script is ran together). If you have 59 | # a really loaded env, you can increase it to 75 or 100. 60 | MAX_ITERATION="5" 61 | 62 | # Lock function 63 | lock() 64 | { 65 | i=0; 66 | # Providing a lock. 67 | while [ 1 ]; do 68 | mkdir ${LOCK} > /dev/null 2>&1 69 | MSL=$? 70 | if [ "${MSL}" = "0" ]; then 71 | # Lock acquired (setting the pid) 72 | echo "$$" > ${LOCK_PID} 73 | return; 74 | fi 75 | 76 | # Getting currently/saved PID locking the file 77 | C_PID=`cat ${LOCK_PID} 2>/dev/null` 78 | if [ "x" = "x${S_PID}" ]; then 79 | S_PID=${C_PID} 80 | fi 81 | 82 | # Breaking out of the loop after X attempts 83 | if [ "x${C_PID}" = "x${S_PID}" ]; then 84 | i=`expr $i + 1`; 85 | fi 86 | 87 | sleep $i; 88 | 89 | i=`expr $i + 1`; 90 | 91 | # So i increments 2 by 2 if the pid does not change. 92 | # If the pid keeps changing, we will increments one 93 | # by one and fail after MAX_ITERACTION 94 | 95 | if [ "$i" = "${MAX_ITERATION}" ]; then 96 | kill="false" 97 | for pid in `pgrep -f "${filename}"`; do 98 | if [ "x${pid}" = "x${C_PID}" ]; then 99 | # Unlocking and exiting 100 | kill -9 ${C_PID} 101 | echo "`date` Killed process ${C_PID} holding lock." 102 | kill="true" 103 | unlock; 104 | i=0; 105 | S_PID=""; 106 | break; 107 | fi 108 | done 109 | 110 | if [ "x${kill}" = "xfalse" ]; then 111 | echo "`date` Unable kill process ${C_PID} holding lock." 112 | # Unlocking and exiting 113 | unlock; 114 | exit 1; 115 | fi 116 | fi 117 | done 118 | } 119 | 120 | # Unlock function 121 | unlock() 122 | { 123 | rm -rf ${LOCK} 124 | } 125 | 126 | 127 | 128 | # Blocking IP 129 | if [ "x${ACTION}" != "xadd" -a "x${ACTION}" != "xdelete" ]; then 130 | echo "$0: invalid action: ${ACTION}" 131 | exit 1; 132 | fi 133 | 134 | 135 | 136 | # We should run on linux 137 | if [ "X${UNAME}" = "XLinux" ]; then 138 | if [ "x${ACTION}" = "xadd" ]; then 139 | ARG1="-I INPUT -s ${IP} -j DROP" 140 | ARG2="-I FORWARD -s ${IP} -j DROP" 141 | else 142 | ARG1="-D INPUT -s ${IP} -j DROP" 143 | ARG2="-D FORWARD -s ${IP} -j DROP" 144 | fi 145 | 146 | # Checking if iptables is present 147 | if [ ! -x ${IPTABLES} ]; then 148 | IPTABLES="/usr"${IPTABLES} 149 | if [ ! -x ${IPTABLES} ]; then 150 | echo "$0: can not find iptables" 151 | exit 0; 152 | fi 153 | fi 154 | 155 | # Executing and exiting 156 | COUNT=0; 157 | lock; 158 | while [ 1 ]; do 159 | ${IPTABLES} ${ARG1} 160 | RES=$? 161 | if [ $RES = 0 ]; then 162 | break; 163 | else 164 | COUNT=`expr $COUNT + 1`; 165 | echo "`date` Unable to run (iptables returning != $RES): $COUNT - $0 $1 $2 $3 $4 $5" 166 | sleep $COUNT; 167 | 168 | if [ $COUNT -gt 4 ]; then 169 | break; 170 | fi 171 | fi 172 | done 173 | 174 | COUNT=0; 175 | while [ 1 ]; do 176 | ${IPTABLES} ${ARG2} 177 | RES=$? 178 | if [ $RES = 0 ]; then 179 | break; 180 | else 181 | COUNT=`expr $COUNT + 1`; 182 | echo "`date` Unable to run (iptables returning != $RES): $COUNT - $0 $1 $2 $3 $4 $5" 183 | sleep $COUNT; 184 | 185 | if [ $COUNT -gt 4 ]; then 186 | break; 187 | fi 188 | fi 189 | done 190 | unlock; 191 | 192 | exit 0; 193 | 194 | # FreeBSD, SunOS or NetBSD with ipfilter 195 | elif [ "X${UNAME}" = "XFreeBSD" -o "X${UNAME}" = "XSunOS" -o "X${UNAME}" = "XNetBSD" ]; then 196 | 197 | # Checking if ipfilter is present 198 | ls ${IPFILTER} >> /dev/null 2>&1 199 | if [ $? != 0 ]; then 200 | exit 0; 201 | fi 202 | 203 | # Checking if echo is present 204 | ls ${ECHO} >> /dev/null 2>&1 205 | if [ $? != 0 ]; then 206 | exit 0; 207 | fi 208 | 209 | if [ "x${ACTION}" = "xadd" ]; then 210 | ARG1="\"@1 block out quick from any to ${IP}\"" 211 | ARG2="\"@1 block in quick from ${IP} to any\"" 212 | IPFARG="${IPFILTER} -f -" 213 | else 214 | ARG1="\"@1 block out quick from any to ${IP}\"" 215 | ARG2="\"@1 block in quick from ${IP} to any\"" 216 | IPFARG="${IPFILTER} -rf -" 217 | fi 218 | 219 | # Executing it 220 | eval ${ECHO} ${ARG1}| ${IPFARG} 221 | eval ${ECHO} ${ARG2}| ${IPFARG} 222 | 223 | exit 0; 224 | 225 | # AIX with ipsec 226 | elif [ "X${UNAME}" = "XAIX" ]; then 227 | 228 | # Checking if genfilt is present 229 | ls ${GENFILT} >> /dev/null 2>&1 230 | if [ $? != 0 ]; then 231 | exit 0; 232 | fi 233 | 234 | # Checking if lsfilt is present 235 | ls ${LSFILT} >> /dev/null 2>&1 236 | if [ $? != 0 ]; then 237 | exit 0; 238 | fi 239 | # Checking if mkfilt is present 240 | ls ${MKFILT} >> /dev/null 2>&1 241 | if [ $? != 0 ]; then 242 | exit 0; 243 | fi 244 | 245 | # Checking if rmfilt is present 246 | ls ${RMFILT} >> /dev/null 2>&1 247 | if [ $? != 0 ]; then 248 | exit 0; 249 | fi 250 | 251 | if [ "x${ACTION}" = "xadd" ]; then 252 | ARG1=" -v 4 -a D -s ${IP} -m 255.255.255.255 -d 0.0.0.0 -M 0.0.0.0 -w B -D \"Access Denied by OSSEC-HIDS\"" 253 | #Add filter to rule table 254 | eval ${GENFILT} ${ARG1} 255 | 256 | #Deactivate and activate the filter rules. 257 | eval ${MKFILT} -v 4 -d 258 | eval ${MKFILT} -v 4 -u 259 | else 260 | # removing a specific rule is not so easy :( 261 | eval ${LSFILT} -v 4 -O | ${GREP} ${IP} | 262 | while read -r LINE 263 | do 264 | RULEID=`${ECHO} ${LINE} | cut -f 1 -d "|"` 265 | let RULEID=${RULEID}+1 266 | ARG1=" -v 4 -n ${RULEID}" 267 | eval ${RMFILT} ${ARG1} 268 | done 269 | #Deactivate and activate the filter rules. 270 | eval ${MKFILT} -v 4 -d 271 | eval ${MKFILT} -v 4 -u 272 | fi 273 | 274 | else 275 | exit 0; 276 | fi 277 | --------------------------------------------------------------------------------