# 10 主动防御

主动防御是基于威胁对象触发的规则告警而进行主动拦截的行为，防御威胁对象继续对代理端进行攻击。

要触发主动防御，主要有两个流程：

1. 修改管理端配置文件，开启主动防御模式。
2. 使用拦截脚本，定义拦截方式和拦截频率次数。

## 管理端配置文件

说明一下主动防御这些标签作用。

| 标签                  | 作用                                                                                                                                                              |
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| command             | 定义要使用的拦截脚本。                                                                                                                                                     |
| location            | <p>定义触发规则的位置，其中有四种选型：local、server、某代理端ID号，all。</p><p>local：触发规则只影响当前代理端。</p><p>server: 触发规则影响管理端。</p><p>某代理端ID号: 触发规则影响某代理端。</p><p>all: 触发规则影响所有代理端，等于全局封禁。</p> |
| rules\_id           | 定义触发主动防御的规则ID号                                                                                                                                                  |
| timeout             | 定义主动防御周期时间。                                                                                                                                                     |
| level               | 定义触发主动防御的告警等级。                                                                                                                                                  |
| rules\_group        | 定义触发主动防御的规则组，多个规则组使用 `\|` 分割。                                                                                                                                   |
| repeated\_offenders | 定义威胁对象多次攻击的时间递增列表，最多可以设置5个递增情况。                                                                                                                                 |

主动防御默认有以下的拦截脚本。

```
[root@wazuh-manager opt]# ls -l /var/ossec/active-response/bin/
total 88
-rwxr-x---. 1 root ossec  6746 Apr 22 09:39 default-firewall-drop.sh
-rwxr-x---. 1 root ossec  1750 Apr 22 09:39 disable-account.sh
-rwxr-x---. 1 root ossec  3990 Apr 22 09:39 firewalld-drop.sh
-rwxr-x---. 1 root ossec  6746 Apr 22 09:39 firewall-drop.sh
-rwxr-x---. 1 root ossec  3577 Apr 22 09:39 host-deny.sh
-rwxr-x---. 1 root ossec   838 Apr 22 09:39 ip-customblock.sh
-rwxr-x---. 1 root ossec  1622 Apr 22 09:39 ipfw_mac.sh
-rwxr-x---. 1 root ossec  1423 Apr 22 09:39 ipfw.sh
-rwxr-x---. 1 root ossec 14435 Apr 22 09:39 kaspersky.py
-rwxr-x---. 1 root ossec   714 Apr 22 09:39 kaspersky.sh
-rwxr-x---. 1 root ossec  1344 Apr 22 09:39 npf.sh
-rwxr-x---. 1 root ossec  1674 Apr 22 09:39 ossec-slack.sh
-rwxr-x---. 1 root ossec  1674 Apr 22 09:39 ossec-tweeter.sh
-rwxr-x---. 1 root ossec  1987 Apr 22 09:39 pf.sh
-rwxr-x---. 1 root ossec   580 Apr 22 09:39 restart-ossec.sh
-rwxr-x---. 1 root ossec  1047 Apr 22 09:39 restart.sh
-rwxr-x---. 1 root ossec  1220 Apr 22 09:39 route-null.sh
```

`host-deny.sh`脚本主要将来源IP地址加入到`/etc/hosts.deny`文件里面，Linux系统就会禁止来源IP地址访问。

```
[root@wazuh-manager opt]# cat /var/ossec/active-response/bin/host-deny.sh 
#!/bin/sh
# Adds an IP to the /etc/hosts.deny file
# Requirements: sshd and other binaries with tcp wrappers support
# Expect: srcip
# Copyright (C) 2015-2020, Wazuh Inc.
# Author: Daniel B. Cid
# Last modified: Nov 09, 2005

ACTION=$1
USER=$2
IP=$3

LOCAL=`dirname $0`;
cd $LOCAL
cd ../
PWD=`pwd`
LOCK="${PWD}/host-deny-lock"
LOCK_PID="${PWD}/host-deny-lock/pid"
UNAME=`uname`


# This number should be more than enough (even if a hundred
# instances of this script is ran together). If you have
# a really loaded env, you can increase it to 75 or 100.
MAX_ITERATION="50"


# Lock function
lock()
{
    i=0;
    # Providing a lock.
    while [ 1 ]; do
        mkdir ${LOCK} > /dev/null 2>&1
        MSL=$?
        if [ "${MSL}" = "0" ]; then
            # Lock acquired (setting the pid)
            echo "$$" > ${LOCK_PID}
            return;
        fi

        # Getting currently/saved PID locking the file
        C_PID=`cat ${LOCK_PID} 2>/dev/null`
        if [ "x" = "x${S_PID}" ]; then
            S_PID=${C_PID}
        fi

        # Breaking out of the loop after X attempts
        if [ "x${C_PID}" = "x${S_PID}" ]; then
            i=`expr $i + 1`;
        fi

        sleep $i;

        i=`expr $i + 1`;

        # So i increments 2 by 2 if the pid does not change.
        # If the pid keeps changing, we will increments one
        # by one and fail after MAX_ITERACTION
        if [ "$i" = "${MAX_ITERATION}" ]; then
            echo "`date` Unable to execute. Locked: $0" \
                        >> ${PWD}/ossec-hids-responses.log

            # Unlocking and exiting
            unlock;
            exit 1;
        fi
    done
}

# Unlock function
unlock()
{
    rm -rf ${LOCK}
}


# Logging the call
echo "`date` $0 $1 $2 $3 $4 $5" >> ${PWD}/../logs/active-responses.log


# IP Address must be provided
if [ "x${IP}" = "x" ]; then
    echo "$0: Missing argument <action> <user> (ip)"
    exit 1;
fi


# Checking for invalid entries (lacking "." or ":", etc)
echo "${IP}" | egrep "\.|\:" > /dev/null 2>&1
if [ ! $? = 0 ]; then
    echo "`date` Invalid ip/hostname entry: ${IP}" >> ${PWD}/../logs/active-responses.log
    exit 1;
fi


# Adding the ip to hosts.deny
if [ "x${ACTION}" = "xadd" ]; then
    # Looking for duplication
    IPKEY=$(grep -w "${IP}" /etc/hosts.deny)
    if [ ! -z "$IPKEY" ]; then
        echo "IP ${IP} already exists on host.deny..." >> ${PWD}/../logs/active-responses.log
        exit 1
    fi
    lock;
    echo "${IP}" | grep "\:" > /dev/null 2>&1
    if [ $? = 0 ]; then
        IP="[${IP}]"
    fi
    if [ "X$UNAME" = "XFreeBSD" ]; then
        echo "ALL : ${IP} : deny" >> /etc/hosts.allow
    else
        echo "ALL:${IP}" >> /etc/hosts.deny
    fi
    unlock;
    exit 0;


# Deleting from hosts.deny
elif [ "x${ACTION}" = "xdelete" ]; then
    lock;
    TMP_FILE=`mktemp ${PWD}/ossec-hosts.XXXXXXXXXX`
    if [ "X${TMP_FILE}" = "X" ]; then
        # Cheap fake tmpfile, but should be harder then no random data
        TMP_FILE="${PWD}/ossec-hosts.`cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -1 `"
    fi
    echo "${IP}" | grep "\:" > /dev/null 2>&1
    if [ $? = 0 ]; then
        IP="\[${IP}\]"
    fi
    if [ "X$UNAME" = "XFreeBSD" ]; then
        cat /etc/hosts.allow | grep -v "ALL : ${IP} : deny$"> ${TMP_FILE}
        mv ${TMP_FILE} /etc/hosts.allow
    else
        cat /etc/hosts.deny | grep -v "ALL:${IP}$"> ${TMP_FILE}
        cat ${TMP_FILE} > /etc/hosts.deny
        rm ${TMP_FILE}
    fi
    unlock;
    exit 0;


# Invalid action
else
    echo "$0: invalid action: ${ACTION}"
fi

exit 1;

```

这里配置文件例子就是使用了`host-deny.sh`拦截脚本，在`command`标签定义`host-deny`，提取来源IP地址，并且设置可以自动解锁封禁（`timeout_allowed`）。当触发规则为`5716`的时候，就会使用`host-deny`，并且封禁范围是当前代理端，封禁时间为600秒。

```
[root@wazuh-manager opt]# cat  /var/ossec/etc/ossec.conf

  <command>
    <name>host-deny</name>
    <executable>host-deny.sh</executable>
    <expect>srcip</expect>
    <timeout_allowed>yes</timeout_allowed>
  </command>

  <active-response>
    <command>host-deny</command>
    <location>local</location>
    <rules_id>5716</rules_id>
    <timeout>600</timeout>
  </active-response>
```

使用kali ssh到centos代理端，第一次连接输入错误的密码，第二次重连就会发现被代理端重置连接。

![](https://github.com/yingshang/SocBook/blob/master/10%20%20%E4%B8%BB%E5%8A%A8%E9%98%B2%E5%BE%A1/.gitbook/assets/image%20\(159\).png)

查看`/etc/hosts.deny`文件，就会发现攻击IP被添加上去。

```
[root@wazuh-centos-agent ~]# cat /etc/hosts.deny 
#
# hosts.deny	This file contains access rules which are used to
#		deny connections to network services that either use
#		the tcp_wrappers library or that have been
#		started through a tcp_wrappers-enabled xinetd.
#
#		The rules in this file can also be set up in
#		/etc/hosts.allow with a 'deny' option instead.
#
#		See 'man 5 hosts_options' and 'man 5 hosts_access'
#		for information on rule syntax.
#		See 'man tcpd' for information on tcp_wrappers
#
ALL:192.168.1.130
```

查看主动防御的日志，就会发现攻击IP（192.168.1.130），攻击时间（1626705265.17483312），触发拦截规则（5716）。

```
[root@wazuh-centos-agent ~]# cat /var/ossec/logs/active-responses.log 
Mon Jul 19 10:34:25 EDT 2021 /var/ossec/active-response/bin/host-deny.sh add - 192.168.1.130 1626705265.17483312 5716
```

等待600秒之后，再次查看主动防御日志，就会看到来源IP地址会自动解禁。

```
[root@wazuh-centos-agent ~]# cat /var/ossec/logs/active-responses.log 
Mon Jul 19 10:34:25 EDT 2021 /var/ossec/active-response/bin/host-deny.sh add - 192.168.1.130 1626705265.17483312 5716
Mon Jul 19 10:44:32 EDT 2021 /var/ossec/active-response/bin/host-deny.sh delete - 192.168.1.130 1626705265.17483312 5716
```

查看管理端代理日志，找到关于5716的告警，显示的是ssh验证失败。

![](https://github.com/yingshang/SocBook/blob/master/10%20%20%E4%B8%BB%E5%8A%A8%E9%98%B2%E5%BE%A1/.gitbook/assets/image%20\(160\).png)

细心的朋友可能发现了，上面这么严格规则（输入错误一次就封禁），在生产环境的时候，访问SSH输入错误的密码是常见的行为，要是应用了这种规则，怕是要直接炸了，所以需要**引入允许错误次数机制**。
